package cn.org.guhao.practice.redis.redpacket.service;

import cn.org.guhao.practice.redis.redpacket.dao.RedPacketDao;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.util.Arrays;
import java.util.Collection;
import java.util.Random;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 红包服务
 * @author guhao
 */
@Slf4j
@Service
public class RedPacketService {

    private AtomicInteger atomicInteger = new AtomicInteger();
    private final String LOCK = "_LOCK";
    private final String PACKETS = "_PACKETS";

    private final RedPacketDao redPacketDao;

    public RedPacketService(RedPacketDao redPacketDao) {
        this.redPacketDao = redPacketDao;
    }

    /**
     * 拆分红包
     * @param total
     * @param count
     * @return
     */
    private Integer[] splitRedPacket(int total, int count) {
        int use = 0;
        Integer[] array = new Integer[count];
        Random random = new Random();
        for (int i = 0; i < count; i++) {
            if (i == count - 1) {
                array[i] = total - use;
            } else {
                // 2 红包随机金额浮动系数
                int avg = (total - use) * 2 / (count - i);
                array[i] = 1 + random.nextInt(avg - 1);
            }
            use = use + array[i];
        }
        return array;
    }

    /**
     * 存红包 采用redis的list结构
     *
     * @param packetId
     * @param total
     */
    public void saveRedPacket(String packetId, int total, int count) {
        Integer[] packets = splitRedPacket(total,count);
        Collection<Integer> collection = Arrays.asList(packets);
        redPacketDao.leftPushAll(packetId.concat(PACKETS), collection);
    }

    /**
     * 抢红包
     * @param redPacketId   红包ID
     * @param i             用户编号
     * @return
     */
    public Integer grab(String redPacketId,int i) throws InterruptedException {
        Integer amount = -1;
        String packetLockKey = redPacketId.concat(LOCK);
        String packetsKey = redPacketId.concat(PACKETS);
        boolean lock;
        // 获取分布式锁
        while (true){
            // 剩余红包数据（Redis中使用List存储）
            long totalNum = redPacketDao.listSize(packetsKey);
            if(totalNum <= 0){
                log.info("红包已抢完");
                break;
            }
            lock = redPacketDao.getLock(packetLockKey);
            if(lock){
                try{
                    // 分配红包
                    amount = redPacketDao.leftPop(packetsKey);
                    if(amount == null){
                        log.info("拿到🔒，但红包已抢完");
                    } else {
                        log.info("[{}]抢到[{}]红包[{}]", i, atomicInteger.incrementAndGet(), amount);
                    }
                    return amount;
                } catch (Exception e) {
                    log.error("抢红包发生异常", e);
                } finally {
                    // 解锁
                    redPacketDao.unLock(packetLockKey);
                }
            }

            Thread.sleep(5*10);
        }
        return amount;
    }

}
